﻿(****************************************************************************
 * 
 *  Bistro FSharp Extensions Copyright © 2003-2009 Hill30 Inc
 *
 *  This file is part of Bistro Framework.
 *
 *  Bistro FSharp Extensions is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Bistro FSharp Extensions is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with Bistro FSharp Extensions.  If not, see <http://www.gnu.org/licenses/>.
 *  
 ***************************************************************************)

module InferenceTests

    open NUnit.Framework
    open Bistro.Controllers
    open Bistro.Controllers.Dispatch
    open System.Collections
    open Bistro.Controllers.OutputHandling
    open Bistro.Configuration.Logging
    open Bistro.Configuration
    open Bistro

    open Bistro.UnitTests.Support

    open Microsoft.FSharp.Quotations

    open System.Configuration
    open System.Reflection
    open System.Web
    open System.IO

    open Bistro.FS.Inference
    open Bistro.FS.Definitions

    [<TestFixture>]
    type InferenceTests() =
        let invoke name = 
            match 
                Expr.TryGetReflectedDefinition 
                <| System.Type.GetType("InferenceTests").GetMethod(name, BindingFlags.Static ||| BindingFlags.Public) with
            | Some ex -> 
                match try_get_return_sig ex with
                | Some l -> 
                    fst <| 
                    List.fold (
                        fun state elem -> sprintf "%s %d: %s - %s;" (fst state) (snd state) (fst elem) ((snd elem) :> System.Type).FullName, (snd state) + 1) 
                        ("", 0) l
                | None -> ""
            | None -> ""
            
        let as_ssn t = sprintf "Bistro.FS.Definitions+session`1[[%s]]" (System.Type.GetType(t).AssemblyQualifiedName)

        [<Test>]
        member x.SingleReturnValue() = Assert.AreEqual(" 0: a - System.Int32;", invoke "single")
        
        [<Test>]
        member x.MultiInputSingleReturnValue() = Assert.AreEqual(" 0: a - System.Int32;", invoke "multiInput")
        
        [<Test>]
        member x.TupleReturnValue() = Assert.AreEqual(" 0: a - System.Int32; 1: b - System.String; 2: c - System.Boolean;", invoke "tupleReturn")
        
        [<Test>]
        member x.Ifs() = Assert.AreEqual(" 0: b - System.Int32;", invoke "ifs")
        
        [<Test>]
        member x.NestedIfs1() = Assert.AreEqual(" 0: c - System.Int32;", invoke "nestedIfs1")
        
        [<Test>]
        member x.NestedIfs2() = Assert.AreEqual(" 0: b - System.Int32;", invoke "nestedIfs2")
        
        [<Test>]
        member x.Lambda1() = Assert.AreEqual(" 0: c - System.Int32;", invoke "lambda1")
        
        [<Test>]
        member x.Lambda2() = Assert.AreEqual("", invoke "lambda2")
        
        [<Test>]
        member x.NamedExpression1() = Assert.AreEqual(" 0: b - System.Int32;", invoke "namedExpression1")
        
        [<Test>]
        member x.NamedExpression2() = Assert.AreEqual(" 0: b - System.Int32;", invoke "namedExpression2")
        
        [<Test>]
        member x.NamedExpression3() = Assert.AreEqual(" 0: b - System.Int32;", invoke "namedExpression3")
        
        [<Test>]
        member x.NamedExpression4() = Assert.AreEqual(" 0: b - System.Int32;", invoke "namedExpression4")
        
        [<Test>]
        member x.NamedExpression5() = Assert.AreEqual(" 0: b - System.Int32;", invoke "namedExpression5")
        
        [<Test>]
        member x.NamedExpression6() = Assert.AreEqual(" 0: b - System.Int32;", invoke "namedExpression6")
        
        [<Test>]
        member x.NamedExpression7() = Assert.AreEqual(" 0: b - System.Int32;", invoke "namedExpression7")
        
        [<Test>]
        member x.SessionExpression1() = Assert.AreEqual(sprintf " 0: b - %s;" (as_ssn "System.Int32"), invoke "sessionExpression1")
        
        [<Test>]
        member x.SessionExpression2() = Assert.AreEqual(sprintf " 0: a - System.String; 1: b - %s;" (as_ssn "System.String"), invoke "sessionExpression2")
        
        [<Test>]
        member x.SessionExpression3() = Assert.AreEqual(sprintf " 0: b - %s; 1: c - System.Int32;" (as_ssn "System.Int32"), invoke "sessionExpression3")
        
        [<Test>]
        member x.SessionExpression4() = Assert.AreEqual(sprintf " 0: c - %s;" (as_ssn "System.Int32"), invoke "sessionExpression4")
        
        [<Test>]
        member x.SessionExpression5() = Assert.AreEqual(sprintf " 0: d_parm - %s;" (as_ssn "System.String"), invoke "sessionExpression5")
        
    [<ReflectedDefinition>]
    let sessionExpression1 a = 
        let b = a + 5
        SessionValue b
        
    [<ReflectedDefinition>]
    let sessionExpression2 a = 
        let b = a + ""
        a, SessionValue b
        
    [<ReflectedDefinition>]
    let sessionExpression3 a = 
        let b = a + 5
        SessionValue b, a |> named "c"    

    [<ReflectedDefinition>]
    let sessionExpression4 a = 
        let b = a + 5
        SessionValue b |> named "c"
        
    [<ReflectedDefinition>]
    let sessionExpression5 ctx c_parm =
        let d_parm = 
            match c_parm with
            | Some v -> v
            | None -> ""
            + "1"
        
        SessionValue d_parm
        
    [<ReflectedDefinition>]
    let namedExpression1 a = 0 |> named "b"
        
    [<ReflectedDefinition>]
    let namedExpression2 a = named "b" 0
        
    [<ReflectedDefinition>]
    let namedExpression3 a = named "b" <| 0
        
    [<ReflectedDefinition>]
    let namedExpression4 a = named <| "b" <| 0
        
    [<ReflectedDefinition>]
    let namedExpression5 a = named <| "b" <| (namedExpression4 0)
        
    [<ReflectedDefinition>]
    let namedExpression6 a = 0 |> ("b" |> named)

    [<ReflectedDefinition>]
    let namedExpression7 a = 
        a * 6 |> named "b"
        
    [<ReflectedDefinition>]
    let lambda2 a = 
        let b,c = 0,0
        printf "hi"
        
    [<ReflectedDefinition>]
    let lambda1 a = 
        let b,c = 0,0
        printf "hi"
        c

    [<ReflectedDefinition>]
    let nestedIfs1 a = 
        let b,c,d = 0,0,0
        if a then 
            if b = 1 then c else d 
        else b
        
    [<ReflectedDefinition>]
    let nestedIfs2 a = 
        let b,c,d = 0,0,0
        if a then b 
        elif b = 1 then c else d
        
    [<ReflectedDefinition>]
    let ifs a = 
        let b,c = 0,0
        if a then b else c
        
    [<ReflectedDefinition>]
    let tupleReturn () = 
        let a,b,c = 0,"",false
        a,b,c

    [<ReflectedDefinition>]
    let multiInput b c d e f () = 
        let a = 0
        a

    [<ReflectedDefinition>]
    let single () = 
        let a = 0
        a

    (*
    1
    +		_arg1	{Lambda (a,
            Call (None,
                  Int32 op_PipeRight[Int32,Int32](Int32, Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,System.Int32]),
                  [Value (0),
                   Let (name, Value ("b"),
                        Lambda (expr,
                                Call (None, Int32 named[Int32](System.String, Int32),
                                      [name, expr])))]))}	Microsoft.FSharp.Quotations.FSharpExpr

    2
    +		_arg1	{Lambda (a,
            Call (None, Int32 named[Int32](System.String, Int32),
                  [Value ("b"), Value (0)]))}	Microsoft.FSharp.Quotations.FSharpExpr


    3
    +		_arg1	{Lambda (a,
            Call (None,
                  Int32 op_PipeLeft[Int32,Int32](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,System.Int32], Int32),
                  [Let (name, Value ("b"),
                        Lambda (expr,
                                Call (None, Int32 named[Int32](System.String, Int32),
                                      [name, expr]))), Value (0)]))}	Microsoft.FSharp.Quotations.FSharpExpr

    4
    +		ex	{Lambda (a,
            Call (None,
                  Int32 op_PipeLeft[Int32,Int32](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,System.Int32], Int32),
                  [Call (None,
                         Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,System.Int32] op_PipeLeft[String,FSharpFunc`2](Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,System.Int32]], System.String),
                         [Lambda (name,
                                  Lambda (expr,
                                          Call (None,
                                                Int32 named[Int32](System.String, Int32),
                                                [name, expr]))), Value ("b")]),
                   Value (0)]))}	Microsoft.FSharp.Quotations.FSharpExpr

    5
    +		ex	{Lambda (a,
            Call (None,
                  Int32 op_PipeLeft[Int32,Int32](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,System.Int32], Int32),
                  [Call (None,
                         Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,System.Int32] op_PipeLeft[String,FSharpFunc`2](Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,System.Int32]], System.String),
                         [Lambda (name,
                                  Lambda (expr,
                                          Call (None,
                                                Int32 named[Int32](System.String, Int32),
                                                [name, expr]))), Value ("b")]),
                   Call (None, Int32 namedExpression4[Int32](Int32), [Value (0)])]))}	Microsoft.FSharp.Quotations.FSharpExpr
    *)